import * as THREE from "../../../modules/three/three.module.js";
import {WorldConfig} from "../lib/CommonConsts.js";
import {arrIncludesPoint, equalRoughly} from "./ShapeExtract.js";

export default class ShapeExtractAdhere {
  /**
   * @type {ConvexAreaMesh[]}
   */
  convexAreas
  points = []

  /**
   * @type {THREE.Vector3}
   */
  _firstAdhere
  adheredPoint
  adheringPoint
  firstPointAdhering = false
  _enabled = true

  constructor(world3d) {
    this.convexAreas = world3d.store.surfacesAreaMeshes
    this._updatePoints()
  }

  onAreaAdded() {
    if (!this._enabled) {
      return;
    }
    this._updatePoints()
    this.adheredPoint = null
    this.adheringPoint = null
  }

  setFirstAdherePoint() {
    if (!this._enabled) {
      return;
    }
    if (this.adheringPoint) {
      this._firstAdhere = this.adheringPoint.clone()
    } else {
      this._firstAdhere = null
    }
  }

  _updatePoints() {
    this.points.length = 0
    for (let i = 0; i < this.convexAreas.length; i++) {
      const cutPoints = this.convexAreas[i].vo.cutPoints;
      cutPoints.forEach(point => {
        if (!arrIncludesPoint(this.points, point)) {
          this.points.push(point);
        }
      });
    }
  }

  _getCutLineByPoints(a, b) {
    let adheringMesh;
    let indexA, indexB
    for (let i = 0; i < this.convexAreas.length; i++) {
      const cutPoints = this.convexAreas[i].vo.cutPoints;
      indexA = cutPoints.findIndex(point => equalRoughly(point, a));
      indexB = cutPoints.findIndex(point => equalRoughly(point, b));
      if (indexA >= 0 && indexB >= 0 && indexA !== indexB) {
        adheringMesh = this.convexAreas[i];
        break;
      }
    }
    if (!adheringMesh) {
      this.adheredPoint = this.adheringPoint;
      return null;
    }
    const min = Math.min(indexA, indexB);
    const max = Math.max(indexA, indexB);
    const diff = Math.abs(indexA - indexB);
    const arr = adheringMesh.vo.cameraStates;

    let cameraState;
    if (diff === 1) {
      cameraState = arr[min];
    } else if (min === 0 && max === arr.length - 1) {
      cameraState = arr[arr.length - 1];
    }
    if (!cameraState) {
      return null;
    }
    const cutPoints = adheringMesh.vo.cutPoints;
    const position = new THREE.Vector3(cameraState[0], cameraState[1], cameraState[2]);
    const rotation = new THREE.Euler(cameraState[3], cameraState[4], cameraState[5]);
    return {position, rotation, lineStart: cutPoints[indexA], lineEnd: cutPoints[indexB]}
    // return {cameraState, adheringMesh, indexA, indexB};
  }

  pointerMove4Cut(pointA) {
    if (!this.convexAreas.length || !this._enabled) {
      return undefined;
    }
    const r = WorldConfig.slicingAdhereRadiusSq
    this.adheringPoint = this.points.find(pointB => {
      return Math.abs(pointA.x - pointB.x) <= r && Math.abs(pointA.y - pointB.y) <= r
        && Math.abs(pointA.z - pointB.z) <= r
    });
    if (this.adheringPoint) {
      console.log('adhering')
    }
    return this.adheringPoint
  }

  pointerDown4Cut() {
    this.firstPointAdhering = false;
    if (!this.convexAreas.length || !this._enabled) {
      return [];
    }
    if (!this.adheringPoint) {
      return [];
    }
    let a = this.adheringPoint;
    const target = [];
    if (this.adheredPoint && !equalRoughly(this.adheredPoint, this.adheringPoint)) {
      const obj = this._getCutLineByPoints(this.adheredPoint, a);
      if (obj) {
        target.push(obj);
      }
    }
    if (this._firstAdhere && !equalRoughly(this._firstAdhere, a)) {
      const obj = this._getCutLineByPoints(this._firstAdhere, a);
      if (obj) {
        this.firstPointAdhering = true;
        target.push(obj);
      }
    }
    this.adheredPoint = this.adheringPoint;
    return target;
  }

}
